﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices.AccountManagement;
using Microsoft.SharePoint;
using System.Web.Security;

namespace ContosoProviders
{
    public class LDAPMember : System.Web.Security.MembershipProvider
    {
        
        private string _applicationName = string.Empty;
        public override string ApplicationName
        {
            get
            {
                if (_applicationName == string.Empty)
                {
                    _applicationName = SPContext.Current.Site.ID.ToString();
                }
                return _applicationName;
            }
            set
            {
                this._applicationName = SPContext.Current.Site.ID.ToString();
            }
        }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            try
            {
                MembershipUserCollection coll = new MembershipUserCollection();
                int resultRecords = 0;
                int startIndex = pageIndex * pageSize;
                int endIndex = startIndex + pageSize;
                SPSecurity.RunWithElevatedPrivileges(new SPSecurity.CodeToRunElevated(delegate()
                {
                    using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
                    {
                        using (UserPrincipal userFilter = new UserPrincipal(context))
                        {
                            userFilter.EmailAddress = emailToMatch.Replace("%", "*");
                            using (PrincipalSearcher search = new PrincipalSearcher(userFilter))
                            {
                                PrincipalSearchResult<Principal> users = search.FindAll();
                                resultRecords = users.Count();
                                if (resultRecords < endIndex + 1)
                                {
                                    startIndex = 0;
                                    endIndex = resultRecords - 1;
                                }
                                for (int i = startIndex; i <= endIndex; i++)
                                {
                                    coll.Add(GetMembershipUser(users.ElementAt(i) as UserPrincipal));
                                }
                            }
                        }
                    }
                }));
                totalRecords = resultRecords;
                return coll;
            }
            catch (Exception ex)
            {
                //TODO: Log Something
                totalRecords = 0;
                return null;
            }
        }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            try
            {
                MembershipUserCollection coll = new MembershipUserCollection();
                int resultRecords = 0;
                int startIndex = pageIndex * pageSize;
                int endIndex = startIndex + pageSize;
                SPSecurity.RunWithElevatedPrivileges(new SPSecurity.CodeToRunElevated(delegate()
                {
                    using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
                    {
                        using (UserPrincipal userFilter = new UserPrincipal(context))
                        {
                            userFilter.SamAccountName = usernameToMatch.Replace("%", "*");
                            using (PrincipalSearcher search = new PrincipalSearcher(userFilter))
                            {
                                PrincipalSearchResult<Principal> users = search.FindAll();
                                resultRecords = users.Count();
                                if (resultRecords < endIndex + 1)
                                {
                                    startIndex = 0;
                                    endIndex = resultRecords - 1;
                                }
                                for (int i = startIndex; i <= endIndex; i++)
                                {
                                    coll.Add(GetMembershipUser(users.ElementAt(i) as UserPrincipal));
                                }
                            }
                        }
                    }
                }));
                totalRecords = resultRecords;
                return coll;
            }
            catch (Exception ex)
            {
                //TODO: Log Something.
                totalRecords = 0;
                return null;
            }
        }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            try
            {
                MembershipUserCollection memUserCollection = new MembershipUserCollection();
                int resultRecords = 0;
                int startIndex = pageIndex * pageSize;
                int endIndex = startIndex + pageSize;
                SPSecurity.RunWithElevatedPrivileges(new SPSecurity.CodeToRunElevated(delegate()
                {
                    using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
                    {
                        using (UserPrincipal userFilter = new UserPrincipal(context))
                        {
                            using (PrincipalSearcher search = new PrincipalSearcher(userFilter))
                            {
                                PrincipalSearchResult<Principal> user = search.FindAll();
                                resultRecords = user.Count();
                                if (resultRecords < endIndex + 1)
                                {
                                    startIndex = 0;
                                    endIndex = resultRecords - 1;
                                }
                                for (int i = startIndex; i <= endIndex; i++)
                                {
                                    memUserCollection.Add(GetMembershipUser(user.ElementAt(i) as UserPrincipal));
                                }
                            }
                        }
                    }
                }));
                totalRecords = resultRecords;
                return memUserCollection;
            }
            catch (Exception ex)
            {
                //Log something.
                totalRecords = 0;
                return null;
            }
            
        }

        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            try
            {
                MembershipUser memUser = null;
                SPSecurity.RunWithElevatedPrivileges(new SPSecurity.CodeToRunElevated(delegate()
                {
                    using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
                    {
                        using (UserPrincipal userFilter = new UserPrincipal(context))
                        {
                            userFilter.SamAccountName = username.Replace("%", "*");
                            using (PrincipalSearcher search = new PrincipalSearcher(userFilter))
                            {
                                UserPrincipal user = search.FindOne() as UserPrincipal;
                                if (!(user == null))
                                {
                                    memUser = GetMembershipUser(user);
                                }

                            }
                        }
                    }
                }));
                return memUser;
            }
            catch (Exception ex)
            {
                //Log something.
                return null;
            }
        }
        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {

            try
            {
                MembershipUser memUser = null;
                SPSecurity.RunWithElevatedPrivileges(new SPSecurity.CodeToRunElevated(delegate()
                {
                    using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
                    {
                        using (UserPrincipal userFilter = new UserPrincipal(context))
                        {
                            userFilter.SamAccountName = providerUserKey.ToString().Trim().ToLower().Replace("%", "*");
                            using (PrincipalSearcher search = new PrincipalSearcher(userFilter))
                            {
                                UserPrincipal user = search.FindOne() as UserPrincipal;
                                if (!(user == null))
                                {
                                    memUser = GetMembershipUser(user);
                                }

                            }
                        }
                    }
                }));
                return memUser;
            }
            catch (Exception ex)
            {
                //Log something.
                return null;
            }
        }

        public override string GetUserNameByEmail(string email)
        {
            try
            {
                string username = string.Empty;
                SPSecurity.RunWithElevatedPrivileges(new SPSecurity.CodeToRunElevated(delegate()
                {
                    using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
                    {
                        using (UserPrincipal userFilter = new UserPrincipal(context))
                        {
                            userFilter.EmailAddress = email;
                            using (PrincipalSearcher search = new PrincipalSearcher(userFilter))
                            {
                                UserPrincipal user = search.FindOne() as UserPrincipal;
                                if (!(user == null))
                                {
                                    username = user.SamAccountName;
                                }
                            }
                        }
                    }
                }));
                return username;
            }
            catch (Exception ex)
            {
                //log something.
                return string.Empty;
            }
        }

        public override bool ValidateUser(string username, string password)
        {
            bool isValid = false;
            try
            {
                SPSecurity.RunWithElevatedPrivileges(new SPSecurity.CodeToRunElevated(delegate()
                {
                    
                    using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
                    {
                        isValid = context.ValidateCredentials(username, password);
                        
                    }
                }));
                
            }
            catch (Exception ex)
            {
                isValid = false;
            }
            return isValid;
        }

        private MembershipUser GetMembershipUser(UserPrincipal user)
        {
            return new MembershipUser("custommembershipprovider",
                user.SamAccountName, user.DistinguishedName,
                user.EmailAddress, string.Empty,
                string.Empty, user.Enabled.Value, !user.Enabled.Value,
                DateTime.MinValue, DateTime.Now, DateTime.Now,
                DateTime.MinValue, DateTime.MinValue);
        }
        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            bool passwordChanged = true;
            try
            {
                passwordChanged = true;
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {

                    using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
                    {
                        using (UserPrincipal userFilter = new UserPrincipal(context))
                        {
                            userFilter.SamAccountName = username.Replace("%", "*");
                            using (PrincipalSearcher search = new PrincipalSearcher(userFilter))
                            {
                                UserPrincipal user = search.FindOne() as UserPrincipal;
                                if (!(user == null))
                                {
                                    user.ChangePassword(oldPassword, newPassword);
                                    passwordChanged = true;

                                }

                            }
                        }
                    }
                    
                });
                
            }
            catch (Exception ex)
            {
                return passwordChanged;
                throw new Exception(ex.ToString());
                
            }
            return true;
        }
        #region Not Implemented Methods
        

        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            throw new NotImplementedException();
        }

        public override System.Web.Security.MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out System.Web.Security.MembershipCreateStatus status)
        {
            throw new NotImplementedException();
        }

        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            throw new NotImplementedException();
        }

        public override bool EnablePasswordReset
        {
            get { throw new NotImplementedException(); }
        }

        public override bool EnablePasswordRetrieval
        {
            get { throw new NotImplementedException(); }
        }

        public override int GetNumberOfUsersOnline()
        {
            throw new NotImplementedException();
        }

        public override string GetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        

        public override int MaxInvalidPasswordAttempts
        {
            get { throw new NotImplementedException(); }
        }

        public override int MinRequiredNonAlphanumericCharacters
        {
            get { throw new NotImplementedException(); }
        }

        public override int MinRequiredPasswordLength
        {
            get { throw new NotImplementedException(); }
        }

        public override int PasswordAttemptWindow
        {
            get { throw new NotImplementedException(); }
        }

        public override System.Web.Security.MembershipPasswordFormat PasswordFormat
        {
            get { throw new NotImplementedException(); }
        }

        public override string PasswordStrengthRegularExpression
        {
            get { throw new NotImplementedException(); }
        }

        public override bool RequiresQuestionAndAnswer
        {
            get { throw new NotImplementedException(); }
        }

        public override bool RequiresUniqueEmail
        {
            get { throw new NotImplementedException(); }
        }

        public override string ResetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        public override bool UnlockUser(string userName)
        {
            throw new NotImplementedException();
        }

        public override void UpdateUser(System.Web.Security.MembershipUser user)
        {
            throw new NotImplementedException();
        }
        #endregion
    }
}